package com.dyrnq.seckill.filter;

import com.dyrnq.seckill.controller.Result;
import com.dyrnq.seckill.exception.UnauthorizedException;
import com.dyrnq.seckill.util.JwtUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * Filters incoming requests and installs a Spring Security principal if a header corresponding to a valid user is
 * found.
 */
@Slf4j
public class JwtFilter extends GenericFilterBean {
    public static final String AUTHORIZATION_HEADER = "Authorization";


    private final String jwtSecret;

    public JwtFilter(String jwtSecret) {
        this.jwtSecret = jwtSecret;
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        boolean skip = httpServletRequest.getAttribute(ApiKeyFilter.APIKEY_HEADER_NAME) != null ? (boolean) httpServletRequest.getAttribute(ApiKeyFilter.APIKEY_HEADER_NAME) : false;
        try {
            String jwt = resolveToken(httpServletRequest);
            validateToken(skip, jwt);
            filterChain.doFilter(servletRequest, servletResponse);
        } catch (Exception exp) {
            ObjectMapper objectMapper = new ObjectMapper();
            HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
            httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            httpResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
            PrintWriter writer = httpResponse.getWriter();
            writer.print(objectMapper.writeValueAsString(Result.error(HttpServletResponse.SC_UNAUTHORIZED, exp.getMessage())));
            writer.flush();
            writer.close();
        }

    }

    private String resolveToken(HttpServletRequest request) {
        String bearerToken = request.getHeader(AUTHORIZATION_HEADER);
        return bearerToken;
    }

    private boolean validateToken(boolean skip, String jwt) {
        return skip ? true : validateToken(jwt);
    }

    private boolean validateToken(String jwt) {
        Claims claims = JwtUtils.parseJwt(jwt, jwtSecret);
        if (claims == null) {
            throw new UnauthorizedException("Invalid JWT Key");
        }
        return true;
    }
}
